﻿using System;
using Castle.Core.Interceptor;
using TestBat.IModels.Base;

namespace TestBat.Models.Interceptors.Domain
{
    public class LockableInterceptor : IInterceptor
    {
        public LockableInterceptor()
        {
            this.locked = false;
        }

        public void Intercept(IInvocation invocation)
        {
            if (invocation.InvocationTarget is ILockable)
            {
                if ("set_Locked".Equals(invocation.Method.Name))
                {
                    locked = true;
                    return;
                }
                else if ("get_Locked".Equals(invocation.Method.Name))
                {
                    invocation.ReturnValue = locked;
                    return;
                }
                else
                {
                    if (locked)
                        if (invocation.Method.Name.StartsWith("set_"))
                            throw new Exception("Can't set property " + invocation.Method.Name + " on locked object " + invocation.InvocationTarget.GetType());
                }
            }

            invocation.Proceed();
            return;

            // retrieve lockable attribute, if present
            //if (!(invocation.InvocationTarget is ILockable))
            //{
            //    invocation.Proceed();
            //    return;
            //}
            //ILockable l = (invocation.InvocationTarget as ILockable);
            ////bool locked = l.Locked;

            //if (!locked)
            //{
            //    invocation.Proceed();
            //    return;
            //}

            //if (invocation.Method.Name.StartsWith("set_"))
            //    throw new Exception("Can't set property " + invocation.Method.Name + " on locked object " + invocation.InvocationTarget.GetType());

            //invocation.Proceed();
            //return;

            //PropertyInfo[] properties = invocation.InvocationTarget.GetType().GetProperties();
            //foreach (PropertyInfo p in properties)
            //{
            //    object[] attributes = p.GetCustomAttributes(false);
            //    if (attributes.Length != 0) // property contains a LockerAttribute
            //    {
            //        if (p.PropertyType != typeof(bool)) // LockerAttribute set to invalid property (needs to be bool)
            //            throw new Exception("LockerAttribute set to invalid property " + p.Name + " (needs to be bool)"); // TODO: better exception type

            //        locked = (bool)p.GetValue(invocation.InvocationTarget, null);
            //    }
            //}

            //if (!locked)
            //{
            //    invocation.Proceed();
            //    return;
            //}

            //if (invocation.Method.Name.StartsWith("set_"))
            //    throw new Exception("Can't set property " + invocation.Method.Name + " on locked object " + invocation.InvocationTarget.GetType());
        }

        private bool locked;
    }
}
